1use super::super::script::ReadParam;
2use super::base::CustomOps;
3use crate::ext::io::*;
4use anyhow::Result;
5use int_enum::IntEnum;
6use std::collections::HashMap;
7use std::io::Seek;
8
9#[repr(u8)]
10#[derive(Debug, IntEnum)]
11enum PaniconOp {
12 End = 0x22,
13 Jump,
14 Call,
15 AutoPlay,
16 Frame,
17 Text,
18 Clear,
19 Gap,
20 Mes,
21 Tlk,
22 Menu,
23 Select,
24 LsfInit,
25 LsfSet,
26 Cg,
27 Em,
28 Clr,
29 Disp,
30 Path,
31 Trans,
32 BgmPlay,
33 BgmStop,
34 BgmVolume,
35 BgmFx,
36 AmbPlay,
37 AmbStop,
38 AmbVolume,
39 AmbFx,
40 SePlay,
41 SeStop,
42 SeWait,
43 SeVolume,
44 SeFx,
45 VocPlay,
46 VocStop,
47 VocWait,
48 VocVolume,
49 VocFx,
50 Quake,
51 Flash,
52 Filter,
53 Effect,
54 Sync,
55 Wait,
56 Movie,
57 Credit,
58 Event,
59 Scene,
60 Title,
61 Notice,
62 SetPass,
63 IsPass,
64 AutoSave,
65 Place,
66 OpenName,
67 Name,
68 LogNew,
69 LogOut,
70}
71
72#[derive(Debug)]
73pub struct PaniconOps<T: std::fmt::Debug + std::hash::Hash> {
74 prev_name: Option<T>,
75 menus: HashMap<T, T>,
76 last_select: usize,
77}
78
79impl<T: std::fmt::Debug + std::hash::Hash> PaniconOps<T> {
80 pub fn new() -> Self {
81 Self {
82 prev_name: None,
83 menus: HashMap::new(),
84 last_select: 0,
85 }
86 }
87}
88
89use PaniconOp::*;
90
91impl<T> CustomOps<T> for PaniconOps<T>
92where
93 T: std::fmt::Debug + TryInto<u64> + std::hash::Hash,
94{
95 fn run<'a>(&mut self, vm: &mut super::super::script::VM<'a, T>, op: u8) -> Result<bool>
96 where
97 MemReaderRef<'a>: ReadParam<T>,
98 T: TryInto<u64>
99 + Default
100 + Eq
101 + Ord
102 + Copy
103 + std::fmt::Debug
104 + std::fmt::Display
105 + std::hash::Hash
106 + From<u8>
107 + std::ops::Neg<Output = T>
108 + std::ops::Add<Output = T>
109 + std::ops::Sub<Output = T>
110 + std::ops::Mul<Output = T>
111 + std::ops::Div<Output = T>
112 + std::ops::Rem<Output = T>
113 + std::ops::Not<Output = T>
114 + std::ops::BitAnd<Output = T>
115 + std::ops::BitOr<Output = T>
116 + std::ops::BitXor<Output = T>
117 + std::ops::Shr<Output = T>
118 + std::ops::Shl<Output = T>,
119 anyhow::Error: From<<T as TryInto<u64>>::Error>,
120 {
121 if let Ok(op) = PaniconOp::try_from(op) {
122 match op {
124 End => vm.skip_n_params(1, false),
125 Jump => vm.skip_n_params(1, false),
126 Call => vm.skip_n_params(1, false),
127 AutoPlay => vm.skip_n_params(1, false),
128 Frame => vm.skip_n_params(1, false),
129 Text => vm.skip_n_params(2, false),
130 Clear => vm.skip_n_params(1, false),
131 Gap => vm.skip_n_params(2, false),
132 Mes => {
134 let mes = vm.pop_data()?;
135 vm.mess.insert(mes);
136 if let Some(name) = self.prev_name.take() {
137 vm.names.insert(mes, name);
138 }
139 Ok(false)
140 }
141 Tlk => {
142 let params = vm.read_params(None)?;
143 let name = params
144 .get(0)
145 .cloned()
146 .ok_or(anyhow::anyhow!("Missing name parameter"))?;
147 self.prev_name = Some(name);
148 Ok(false)
149 }
150 Menu => {
151 let params = vm.read_params(Some(3))?;
152 let id = params[0];
153 let mes = params[1];
154 vm.mess.insert(mes);
155 self.menus.insert(id, mes);
156 Ok(false)
157 }
158 Select => {
159 if let Some(var) = vm.vars.get_mut(&T::from(131)) {
160 *var = *var + T::from(1);
161 return Ok(false);
162 }
163 let offset = vm.reader.stream_position()? - 1;
164 for _ in self.last_select + 1..self.menus.len() {
165 vm.stack.push(offset);
166 }
168 vm.vars.insert(T::from(131), T::from(0));
169 vm.skip_n_params(2, false)
170 }
171 LsfInit => vm.skip_n_params(1, false),
172 LsfSet => vm.skip_params(false),
173 Cg => vm.skip_params(false),
174 Em => vm.skip_n_params(5, false),
175 Clr => vm.skip_n_params(1, false),
176 Disp => vm.skip_n_params(4, false),
177 Path => vm.skip_params(false),
178 Trans => Ok(false),
179 BgmPlay => vm.skip_n_params(3, false),
180 BgmStop => vm.skip_n_params(1, false),
181 BgmVolume => vm.skip_n_params(2, false),
182 BgmFx => vm.skip_n_params(1, false),
183 AmbPlay => vm.skip_n_params(3, false),
184 AmbStop => vm.skip_n_params(1, false),
185 AmbVolume => vm.skip_n_params(2, false),
186 AmbFx => vm.skip_n_params(1, false),
187 SePlay => vm.skip_n_params(5, false),
188 SeStop => vm.skip_n_params(2, false),
189 SeWait => vm.skip_n_params(1, false),
190 SeVolume => vm.skip_n_params(3, false),
191 SeFx => vm.skip_n_params(1, false),
192 VocPlay => vm.skip_n_params(4, false),
193 VocStop => vm.skip_n_params(2, false),
194 VocWait => vm.skip_n_params(1, false),
195 VocVolume => vm.skip_n_params(3, false),
196 VocFx => vm.skip_n_params(1, false),
197 Quake => vm.skip_n_params(4, false),
198 Flash => vm.skip_n_params(2, false),
199 Filter => vm.skip_n_params(2, false),
200 Effect => vm.skip_n_params(1, false),
201 Sync => vm.skip_n_params(2, false),
202 Wait => vm.skip_n_params(1, false),
203 Movie => vm.skip_n_params(1, false),
204 Credit => vm.skip_n_params(1, false),
205 Event => vm.skip_n_params(1, false),
206 Scene => vm.skip_n_params(1, false),
207 Title => {
208 let title = vm.pop_data()?;
209 vm.mess.insert(title);
210 Ok(false)
211 }
212 Notice => {
213 let notice = vm.pop_data()?;
214 vm.mess.insert(notice);
215 vm.skip_n_params(2, false)
216 }
217 SetPass => vm.skip_n_params(2, false),
218 IsPass => vm.skip_n_params(1, false),
219 AutoSave => Ok(false),
220 Place => vm.skip_n_params(1, false),
221 OpenName => vm.skip_n_params(1, false),
222 Name => {
223 eprintln!("Name operation.");
224 let mes = vm.pop_data()?;
225 let name = vm.pop_data()?;
226 vm.mess.insert(mes);
227 vm.names.insert(mes, name);
228 Ok(false)
229 }
230 LogNew => vm.skip_n_params(1, false),
231 LogOut => vm.skip_params(false),
232 }
233 } else {
234 Ok(false)
236 }
237 }
238}